package com.xiyu.service.service.health;

import com.xiyu.service.vo.health.medicinePlan.MedicinePlanSingleGetOutput;
import com.xiyu.service.model.medicine.HealthMedicinePlanDraft;
import com.xiyu.service.model.medicine.HealthMedicinePlanProps;
import com.xiyu.service.vo.health.medicinePlan.MedicinePlanUpdateInput;
import com.xiyu.service.vo.health.medicinePlan.MedicinePlanGetOutput;
import com.xiyu.service.model.medicine.HealthMedicinePlan;
import com.xiyu.service.repository.medicine.HealthMedicinePlanRepository;
import com.xiyu.service.vo.health.medicinePlan.MedicinePlanCreateInput;
import com.xiyu.service.model.medicine.HealthMedicinePlanDetail;
import com.xiyu.service.repository.medicine.HealthMedicinePlanDetailRepository;
import com.xiyu.service.vo.health.medicinePlan.MedicinePlanPageQueryOutput;
import com.xiyu.service.vo.health.medicinePlan.MedicinePlanPageQueryInput;
import org.babyfish.jimmer.DraftObjects;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.babyfish.jimmer.Page;
import java.util.*;

import org.springframework.transaction.annotation.Transactional;
import com.xiyu.service.framework.web.web.core.pojo.PageResult;
import com.xiyu.service.convert.health.MedicinePlanConvert;

import static com.xiyu.service.framework.exception.util.ServiceExceptionUtil.exception;
import static com.xiyu.service.errorCode.health.MedicinePlanErrorCode.*;

/**
 * 用药设置 Service 实现类
 */
@Service
@Validated
public class MedicinePlanServiceImpl implements MedicinePlanService {

    @Resource
    private HealthMedicinePlanRepository healthMedicinePlanRepository;

    @Resource
    private HealthMedicinePlanDetailRepository healthMedicinePlanDetailRepository;

    @Override
    public PageResult<MedicinePlanPageQueryOutput> pageQuery(MedicinePlanPageQueryInput inputVO) {
        Page<HealthMedicinePlan> pageHealthMedicinePlan = healthMedicinePlanRepository.pageQuery(inputVO);
        List<MedicinePlanPageQueryOutput> listHealthMedicinePlan = MedicinePlanConvert.INSTANCE.pageQueryOutputConvert(pageHealthMedicinePlan.getRows());
        return new PageResult<>(listHealthMedicinePlan, pageHealthMedicinePlan.getTotalRowCount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(MedicinePlanCreateInput inputVO) {
        Optional<HealthMedicinePlan> existsPlan = healthMedicinePlanRepository.findByElderId(inputVO.getElderId());
        if(existsPlan.isPresent()){
            throw exception(HEALTH_MEDICINE_PLAN_ELDER_DUPLICATE);
        }
        if(inputVO.getDetails().isEmpty()){
            throw exception(HEALTH_MEDICINE_PLAN_DETAIL_NOT_EMPTY);
        }
        HealthMedicinePlan newHealthMedicinePlan = MedicinePlanConvert.INSTANCE.createInputConvert(inputVO);
        newHealthMedicinePlan = healthMedicinePlanRepository.insert(newHealthMedicinePlan);
        return newHealthMedicinePlan.id();

    }

    @Override
    public MedicinePlanGetOutput get(Long id) {
        Optional<HealthMedicinePlan> optionalHealthMedicinePlan = healthMedicinePlanRepository.findById(id);
        if(!optionalHealthMedicinePlan.isPresent()){
            throw exception(HEALTH_MEDICINE_PLAN_NOT_EXIST);
        }
        return MedicinePlanConvert.INSTANCE.getOutputConvert(optionalHealthMedicinePlan.get());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(MedicinePlanUpdateInput inputVO) {
        Optional<HealthMedicinePlan> optionalOldHealthMedicinePlan = healthMedicinePlanRepository.findById(inputVO.getId());
        if(!optionalOldHealthMedicinePlan.isPresent()){
            throw exception(HEALTH_MEDICINE_PLAN_NOT_EXIST);
        }
        for(MedicinePlanUpdateInput.detail detail : inputVO.getDetails()){
            if(Objects.equals("delete", detail.getOperateType())){
                Optional<HealthMedicinePlanDetail> planDetail = healthMedicinePlanDetailRepository.findById(detail.getId());
                if(!planDetail.isPresent()){
                    throw exception(HEALTH_MEDICINE_PLAN_DETAIL_NOT_EXIST);
                }
                healthMedicinePlanDetailRepository.delete(planDetail.get());
            }else if(Objects.equals(detail.getOperateType(),("new"))){
                Optional<HealthMedicinePlanDetail> planDetail = healthMedicinePlanDetailRepository.findFirstByPlanIdAndMedicineId(detail.getPlanId(), detail.getMedicineId());
                if(planDetail.isPresent()){
                    throw exception(HEALTH_MEDICINE_PLAN_DETAIL_DUPLICATE);
                }
                HealthMedicinePlanDetail newDetail = MedicinePlanConvert.INSTANCE.updateInputConvert(detail);
                healthMedicinePlanDetailRepository.insert(newDetail);
            }else {
                Optional<HealthMedicinePlanDetail> planDetail = healthMedicinePlanDetailRepository.findById(detail.getId());
                if(!planDetail.isPresent()){
                    throw exception(HEALTH_MEDICINE_PLAN_DETAIL_NOT_EXIST);
                }
                HealthMedicinePlanDetail updateDetail = MedicinePlanConvert.INSTANCE.updateInputConvert(detail);
                healthMedicinePlanDetailRepository.update(updateDetail);
            }
        }
        if(healthMedicinePlanDetailRepository.findByPlanId(inputVO.getId()).isEmpty()){
            throw exception(HEALTH_MEDICINE_PLAN_DETAIL_NOT_EMPTY);
        }
        HealthMedicinePlan updateHealthMedicinePlan = MedicinePlanConvert.INSTANCE.updateInputConvert(inputVO);
        updateHealthMedicinePlan = HealthMedicinePlanDraft.$.produce(updateHealthMedicinePlan, draft -> {
            DraftObjects.unload(draft, HealthMedicinePlanProps.DETAILS);
        });
        healthMedicinePlanRepository.update(updateHealthMedicinePlan);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleted(Long id) {
        Optional<HealthMedicinePlan> optionalDeleteHealthMedicinePlan = healthMedicinePlanRepository.findById(id);
        if(!optionalDeleteHealthMedicinePlan.isPresent()){
            throw exception(HEALTH_MEDICINE_PLAN_NOT_EXIST);
        }
        healthMedicinePlanRepository.deleteById(id);
        return true;
    }

    @Override
    public MedicinePlanSingleGetOutput singleGet(Long id) {
        Optional<HealthMedicinePlan> optionHealthMedicinePlan = healthMedicinePlanRepository.findDetailById(id);
        if(!optionHealthMedicinePlan.isPresent()){
            throw exception(HEALTH_MEDICINE_PLAN_NOT_EXIST);
        }
        return MedicinePlanConvert.INSTANCE.singleGetOutputConvert(optionHealthMedicinePlan.get());

    }

}
